/*
 * @(#)ObjectWatcher.java $version 2010. 8. 11
 *
 * Copyright 2007-2010 NHN Corp. All rights Reserved. 
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.nhncorp.usf.core.config;

import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.nhncorp.lucy.common.reload.Reloadable;
import com.nhncorp.lucy.common.reload.WatchedObject;

/**
 * @author Web Platform Development TeamDKrK
 */
public class ObjectWatcher {
    private static Log log = LogFactory.getLog(ObjectWatcher.class);

    /**
     * {@link Watcher} 디폴트 실행 주기값
     */
    private static final long DEFAULT_PERIOD = 60000;

    /**
     * {@link Watcher} 디폴트 지연 시간
     */
    private static final long DEFAULT_DELAY = 1000;

    /**
     * {@link Watcher} ObjectWatcher 시작 여부
     */
    private boolean started = false;

    /**
     * {@link Watcher} 실행주기
     */
    private long period = DEFAULT_PERIOD;

    /**
     * {@link Watcher} 실행전 지연시간
     */
    private long delay = DEFAULT_DELAY;

    /**
     * {@link Watcher} 를 주기적으로 실행할 {@link Timer}
     */
    private Timer timer;

    /**
     * 주어진 {@code period}, {@code delay}를 기본 값으로 초기화한다.
     *
     * @param period {@link Watcher} 실행주기
     * @param delay  {@link Watcher} 지연시간
     */
    public ObjectWatcher(long period, long delay) {
        this();
        this.period = period;
        this.delay = delay;
    }

    /**
     * {@code period}, {@code delay}를 기본 값으로 초기화한다.
     */
    public ObjectWatcher() {
        timer = new Timer(true);
    }

    /**
     * {@link Watcher} ObjectWatcher 시작
     */
    public void start() {
        timer.schedule(new Watcher(), delay, period);

        // add shutdown-hook
        Runtime.getRuntime().addShutdownHook(new Thread() {

            public void run() {
                cancel();
            }

        });

        started = true;
        log.debug("ObjectWatcher started");
    }

    /**
     * {@link Watcher} ObjectWatcher 시작 여부 확인
     *
     * @return true the ObjectWatcher start 수행
     */
    public boolean isStarted() {
        return started;
    }

    /**
     * {@link Watcher}를 중단한다.
     */
    public void cancel() {
        started = false;
        timer.cancel();
    }

    /**
     * {@link Watcher}의 실행 주기를 반환한다.
     *
     * @return long the period value
     */
    public long getPeriod() {
        return period;
    }

    /**
     * {@link Watcher}의 실행 주기를 설정한다.
     *
     * @param period the period value
     */
    public void setPeriod(long period) {
        this.period = period;
    }

    /**
     * {@link Watcher} 실행 전 지연 시간을 반환한다.
     *
     * @return long the delay value
     */
    public long getDelay() {
        return delay;
    }

    /**
     * {@link Watcher} 실행 전 지연 시간을 설정한다.
     *
     * @param delay the delay value
     */
    public void setDelay(long delay) {
        this.delay = delay;
    }

    /**
     * {@link ObjectWatcher}에서 주기적으로 수행하는 task이다.
     *
     * @author Web Platform Development TeamDKrK
     * @version $Rev$, $Date$
     */
    class Watcher extends TimerTask {
        public void run() {
            log.debug("Checking Reloadable Object...");
            List<Reloadable> readableList = WatchedObject.getInstance().getReloadables();

            List<Reloadable> queue = new LinkedList<Reloadable>();

            for (Reloadable reloadable : readableList) {

                if (reloadable.isChanged()) {
                    log.debug(reloadable.getClass() + " is changed!!");
                    queue.add(reloadable);
                }

            }

			for (Reloadable reloadable : queue) {
				if (reloadable != null) {
					reloadable.load();
				}

			}
		}
    }
}